from flask import current_app, Blueprint, request
from flask_json import as_json
from flask_jwt_extended import jwt_required

from app import db
from app.admin.is_staff_user import is_staff_user
from app.auth.auth_decorator import has_role
from app.common.enums import AuthRoleStatus, RoleCodeEnum
from app.models import CommonResult, AuthRole, AuthRolePermission, AuthUserRole, AuthPermission, BlogUser

log = current_app.logger
permission = Blueprint('auth_role_permission', __name__, url_prefix='/auth/role')


# 注册蓝图
def register_controller(app):
    app.register_blueprint(permission)


# 角色分配权限
@permission.post('/distribution_permission')
@jwt_required()
@has_role({RoleCodeEnum.ADMIN})
@is_staff_user
@as_json
def distribution_permission():
    data = request.get_json()
    if data is None or data.get('id') is None:
        return CommonResult(code=500, msg='设置的角色不存在')
    # 查询到分配权限的角色
    record = AuthRole.query.get(data.get('id'))
    if record is None:
        return CommonResult(code=500, msg='角色不存在')
    # 读取传入的权限id
    pids: list[int] = data.get('p_ids')
    # 如果记录为空，就删除角色的全部权限记录
    if pids is None or len(pids) <= 0:
        db.session.query(AuthRolePermission).filter_by(role_id=record.id).delete()
        db.session.commit()
        return CommonResult(msg='设置成功')
    # 如果存在记录，获取已存在的权限列表，然后进行对比
    # 该添加的添加，该删除的删除
    exist_role_list = AuthRolePermission.query.filter(AuthRolePermission.role_id == record.id).all()
    if exist_role_list is not None and len(exist_role_list) > 0:
        exist_permission_ids: list[int] = [role_permission.permission_id for role_permission in exist_role_list]
        # 新增=存在 差 并集
        # 删除=修改 差 并集
        union: set = set(pids).union(set(exist_permission_ids))
        need_insert: set = union.difference(set(exist_permission_ids))
        need_delete: set = union.difference(set(pids))
        log.debug("角色设置权限，已存在=%s，修改=%s，并集=%s，新增=%s，删除=%s",
                  exist_permission_ids, pids, union, need_insert, need_delete)
        if len(need_insert) > 0:
            for pid in need_insert:
                if AuthPermission.query.get(pid):
                    save_data = AuthRolePermission(role_id=record.id, permission_id=pid)
                    db.session.add(save_data)
        if len(need_delete) > 0:
            for pid in need_delete:
                db.session.query(AuthRolePermission).filter(
                    AuthRolePermission.role_id == record.id,
                    AuthRolePermission.permission_id == pid
                ).delete()
        # 提交修改
        db.session.commit()
    else:
        # 以前没有权限记录，现在选择了，直接绑定关系
        for pid in pids:
            if AuthPermission.query.get(pid):
                save_data = AuthRolePermission(role_id=record.id, permission_id=pid)
                db.session.add(save_data)
        db.session.commit()
    return CommonResult(msg='设置成功')


# 查询角色拥有权限列表
@permission.get('/have_permissions/<int:role_id>')
@jwt_required()
@is_staff_user
@as_json
def role_have_permissions(role_id):
    data_list = AuthRolePermission.query.filter(AuthRolePermission.role_id == role_id).all()
    permission_ids = [record.permission_id for record in data_list]
    return CommonResult(data=permission_ids)


# 给用户分配角色
@permission.post('/assigned_to_user/<int:user_id>')
@jwt_required()
@has_role({RoleCodeEnum.ADMIN})
@is_staff_user
@as_json
def user_distribution_role(user_id):
    # 校验用户是否存在
    user = BlogUser.query.get(user_id)
    if user is None:
        return CommonResult(code=500, msg='用户不存在，请检查')
    # 获取传入的角色ID
    data = request.get_json()
    if data and data.get('role_id') is not None:
        role_id: int = data.get('role_id')
        role = AuthRole.query.get(role_id)
        if role is None:
            return CommonResult(code=500, msg='分配的角色不存在，请检查')
        # 保存分配记录
        user_role = AuthUserRole(user_id=user_id, role_id=role_id)
        db.session.add(user_role)
        db.session.commit()
        return CommonResult(msg='保存成功')
    return CommonResult(code=500, msg='请传入分配的角色编号')


# 取消用户角色
@permission.post('/cancel_to_user/<int:user_id>')
@jwt_required()
@has_role({RoleCodeEnum.ADMIN})
@is_staff_user
@as_json
def cancel_role_to_user(user_id):
    # 获取传入的角色ID
    data = request.get_json()
    if data and data.get('role_id') is not None:
        role_id: int = data.get('role_id')
        # 删除用户角色关联记录
        AuthUserRole.query.filter(
            AuthUserRole.user_id == user_id,
            AuthUserRole.role_id == role_id
        ).delete()
        db.session.commit()
        return CommonResult(msg='取消成功')
    return CommonResult(code=500, msg='请传入角色编号')


# 用户拥有角色
@permission.get('/user/<int:user_id>')
@jwt_required()
@is_staff_user
@as_json
def user_roles(user_id):
    # 校验用户是否存在
    user = BlogUser.query.get(user_id)
    if user is None:
        return CommonResult(code=500, msg='用户不存在，请检查')
    # 查询中间表记录
    user_role_list: list = AuthUserRole.query.filter(AuthUserRole.user_id == user_id).all()
    if user_role_list and len(user_role_list) > 0:
        # 提取角色id，然后查询用户角色表
        user_role_ids = [role.role_id for role in user_role_list]
        role_list = AuthRole.query.filter(
            AuthRole.id.in_(user_role_ids),
            AuthRole.role_status == AuthRoleStatus.enabled.name
        ).all()
        return CommonResult(data=role_list)
    return CommonResult(data=[])
